""" Level generator

Separates the level into grids, each grid can contain 0-1 rooms.
Room 1 connects to room 2, 2 to 3, 3 to 4 etc.
Because rooms will be situated randomly this shouldn't create layouts
that are identical each time.
The connections will be created from center to center of the grid's cells,
because we can assume that a room in a cell will always occupy at least the
center of the cell.

The engine that calls this script MUST add the following variables to the scope:
mapSize
cellSize

"""

import random

random.seed()

tiles = []
cells = []
roomCount = 0

#Create a mapSizexmapSize array of zeroes
for x in xrange(mapSize):
    tiles.append([])
    for z in xrange(mapSize):
        tiles[x].append(0)

#Create the cell array
for x in xrange(mapSize/cellSize + 1):
    cells.append([])
    for z in xrange(mapSize/cellSize + 1):
        cells[x].append(0)

#Generate the rooms. First chooses a cell, then generates a room inside that
#cell
for room in xrange(random.randint(7,10)):

    cellX = random.randint(0, (mapSize/cellSize)-1)
    cellZ = random.randint(0, (mapSize/cellSize)-1)

    #Find an unused cell
    while cells[cellX][cellZ] > 0:
        cellX = random.randint(0, (mapSize/cellSize)-1)
        cellZ = random.randint(0, (mapSize/cellSize)-1)

    roomCount += 1
    cells[cellX][cellZ] = roomCount

    startX = 0
    startZ = 0
    endX = 0
    endZ = 0
    
    while endX - startX < 2 or endZ - startZ < 2:
        startX = random.randint((cellX * cellSize), (cellX * cellSize) + (cellSize/2)- 1)
        startZ = random.randint((cellZ * cellSize), (cellZ * cellSize) + (cellSize/2)- 1)

        endX = random.randint((cellX * cellSize) + (cellSize/2) + 1, (cellX * cellSize) + cellSize - 1)
        endZ = random.randint((cellZ * cellSize) + (cellSize/2) + 1, (cellZ * cellSize) + cellSize - 1)

    for x in xrange(startX, endX):
        for z in xrange(startZ, endZ):
            if x > 2 and x < mapSize-2 and z > 2 and z < mapSize-2:
                tiles[x][z] = 2

    if roomCount == 1: #Player starts in room 1
        playerTileX = ((startX+endX) / 2)
        playerTileZ = ((startZ+endZ) / 2)
        level.TPC.Position = Vector3(playerTileX * 200, 75, playerTileZ * 200)

    if roomCount == 3: #We'll put the portal in the third room. Why? Why not!
        if levelNumber == 5:
            tiles[(startX+endX)/2][(startZ+endZ)/2] = 4
        elif levelNumber == 10:
            tiles[(startX+endX)/2][(startZ+endZ)/2] = 5
        elif levelNumber == 15:
            tiles[(startX+endX)/2][(startZ+endZ)/2] = 6
        elif levelNumber == 20:
            tiles[(startX+endX)/2][(startZ+endZ)/2] = 7
        else:
            tiles[(startX+endX)/2][(startZ+endZ)/2] = 3
        level.PortalPos = Vector3(((startX+endX)/2)*200, 0, ((startZ+endZ)/2)*200)

#Connect the rooms. Each cell is identified by it's roomcount, so to find two
#cells that need to be connected, just search for cell id's x and x+1

for room in xrange(1, roomCount):

    #Find our cells. HOLY BAD ALGORITHM BATMAN
    for x in xrange(0, mapSize/cellSize):
        for z in xrange(0, mapSize/cellSize):
            if cells[x][z] == room:
                room1X = x
                room1Z = z
            if cells[x][z] == room+1:
                room2X = x
                room2Z = z
                #Robin I think we need the algorithm-betterification-spray

    curX = room1X * cellSize + (cellSize / 2)
    curZ = room1Z * cellSize + (cellSize / 2)
    destX = room2X * cellSize + (cellSize / 2)
    destZ = room2Z * cellSize + (cellSize / 2)

    #I don't discriminate against "efficiency challenged" algorithms
    while curX != destX or curZ != destZ:
        if tiles[curX][curZ] < 3:   #So we don't overwrite the portal
            tiles[curX][curZ] = 2
        if random.randint(0,1) == 0:
            if curX < destX: curX += 1
            if curX > destX: curX -= 1
        else:
            if curZ < destZ: curZ += 1
            if curZ > destZ: curZ -= 1
    #Some of my best friends are bad algorithms

#Create walls around floors. We don't want floor tiles everywhere, emptiness is ok
#0 is empty, 1 is wall, > 1 is floor or portal

for x in xrange(1, mapSize-1):
    for z in xrange(1, mapSize-1):

        if tiles[x-1][z] > 1 or tiles[x+1][z] > 1 or tiles[x][z-1] > 1 or \
        tiles[x][z+1] > 1: #A surrounding tile is floor or portal
            if tiles[x][z] == 0: #This tile is empty
                tiles[x][z] = 1

#Add levelNumber monsters
level.Entities.Clear()
monsters = []
x = 0
z = 0
for i in xrange(levelNumber):
    while ( tiles[x][z] is not None and (tiles[x][z] != 2 or monsters.__contains__((x,z))) or (x == playerTileX and z == playerTileZ)):  #Loop until we find a floor tile with no monster
        x = random.randint(0, mapSize-1)
        z = random.randint(0, mapSize-1)
    monsters.append((x,z))
    
for monster in monsters:
    monstername = random.choice(["golem1","ghost","watere","wisp"])
    monsterstrength = 1
    levelnumber = level.LevelNumber
    if levelnumber < 5:
        monsterstrength = 1
    elif 5 <= levelnumber < 10:
        monsterstrength = 2
    elif 10 <= levelnumber < 15:
        monsterstrength = 3
    elif 15 <= levelnumber < 20:
        monsterstrength = 4
    elif levelnumber >= 20:
        monsterstrength = 5
    newNPC = Monster(parentGame, level, monstername, monsterstrength)
    newNPC.Position = Vector3(monster[0] * 200, 80, monster[1] * 200)
    #Should probably set scale somewhere else, like in xml?
    if monstername == "golem1":
        newNPC.Scale = 0.5
    if monstername == "ghost":
        newNPC.Scale = 0.9    
    if monstername == "watere":
        newNPC.Scale = 8
        newNPC.Position = Vector3(monster[0] * 200, 0, monster[1] * 200)   
    newNPC.Scale = newNPC.Scale * ( 1 + (monsterstrength - 5)/10.0)    
    newNPC.Speed = 3
    newNPC.CurrentAnim = "idle"
    newNPC.FrameDelay = TimeSpan.FromMilliseconds(200);
    newNPC.Play()
    level.Born.Add(newNPC)	

#Create the tiles
for x in xrange(0, mapSize):
    for z in xrange(0, mapSize):
        if tiles[x][z] == 1:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 100, z*200), TileTypes.Wall)
        elif tiles[x][z] == 2:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Floor)
        elif tiles[x][z] == 3:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Portal)
        elif tiles[x][z] == 4:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Earthportal)
        elif tiles[x][z] == 5:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Waterportal)
        elif tiles[x][z] == 6:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Airportal)
        elif tiles[x][z] == 7:
            level.Tiles[x,z] = TriDTile(parentGame, Vector3(x*200, 0, z*200), TileTypes.Fireportal)
            
